# -*- coding: UTF-8 -*-

import pandas as pd
import numpy as np

# 设置输出窗口大小
desired_width = 320
pd.set_option('display.width', desired_width)
pd.set_option('display.max_columns', 20)


def get_maker_retail_feature(tx, threshold):
    """
    统计庄家、散户特征
    :param tx: 交易信息
    :param threshold: 庄家散户区分阈值
    :return: 庄家、散户转入、转出的统计信息及列名
    """
    if len(tx) == 0:
        return [0, 0, 0, 0, 0, 0, 0, 0]
    received_tx = tx.loc[tx['tag'] == 0]
    send_tx = tx.loc[tx['tag'] == 1]
    maker_received_tx = received_tx.loc[received_tx['value'] >= threshold]
    maker_received = maker_received_tx['value'].sum()
    maker_received_tx_count = len(maker_received_tx)
    maker_send_tx = send_tx.loc[send_tx['value'] >= threshold]
    maker_send = maker_send_tx['value'].sum()
    maker_send_tx_count = len(maker_send_tx)
    retail_received_tx = received_tx.loc[received_tx['value'] < threshold]
    retail_received = retail_received_tx['value'].sum()
    retail_received_tx_count = len(retail_received_tx)
    retail_send_tx = send_tx.loc[send_tx['value'] < threshold]
    retail_send = retail_send_tx['value'].sum()
    retail_send_tx_count = len(retail_send_tx)
    return [maker_received, maker_received_tx_count, maker_send, maker_send_tx_count,
            retail_received, retail_received_tx_count, retail_send, retail_send_tx_count]


def get_basic_feature(tx):
    """
    交易基本信息统计
    :param tx: 交易信息
    :return: 转入、转出总额，交易量，std，skew信息及列名
    """
    if len(tx) == 0:
        return [0, 0, 0, 0, 0, 0, 0]
    std_value = tx['value'].std()
    skew_value = tx['value'].skew()
    total_tx_count = len(tx)
    curr_received_tx = tx.loc[tx['tag'] == 0]
    total_received = curr_received_tx['value'].sum()
    received_tx_count = len(curr_received_tx)
    curr_send_tx = tx.loc[tx['tag'] == 1]
    total_send = curr_send_tx['value'].sum()
    send_tx_count = len(curr_send_tx)
    return [total_tx_count, std_value, skew_value, total_received, received_tx_count, total_send, send_tx_count]


def get_histogram_feature(tx, threshold, bins):
    """
    将交易信息转换为histogram特征
    :param tx: 交易信息
    :param threshold: 进行histogram处理的value阈值
    :param bins: bins
    :return: 直方图对应bin的值及列名
    """
    if len(tx) == 0:
        return [0]
    hist, bin_edges = np.histogram(tx['value'].loc[tx['value'] < threshold], bins=bins)
    out_threshold_tx_count = len(tx['value'].loc[tx['value'] >= threshold])
    return np.append(hist, out_threshold_tx_count)


def get_exchange_features(tx, start_time, end_time, step_minute, return_dict=None, process_num=0,
                          value_threshold=1000, maker_threshold=10, histogram_threshold=10, bins=10,
                          minute_module=True):
    """
    从交易所信息中提取特征
    :param tx: 交易数据
    :param start_time: 开始时间
    :param end_time: 结束时间
    :param step_minute: 统计时间粒度
    :param return_dict: 多进程返回消息
    :param process_num: 进程号
    :param value_threshold: 特殊值阈值
    :param maker_threshold: 庄家阈值
    :param histogram_threshold: hist阈值
    :param bins: host bins
    :param minute_module: 返回格式每分钟 or 每个步长
    :return: 开始时间至结束时间的特征数据
    """
    # TODO: 特殊值阈值处理
    if start_time > end_time:
        return
    features = []
    curr_time = start_time
    last_sum = -1

    while curr_time < end_time:
        curr_tx = tx.loc[(tx['timestamp'] > (curr_time - step_minute * 60)) & (tx['timestamp'] <= curr_time)]
        curr_sum = curr_tx['value'].sum()
        # 若相邻的两次计算区间的sum值相同，则不用重复计算
        if curr_sum == last_sum:
            curr_res = features[-1][:]
            curr_res[0] = pd.to_datetime(curr_time, unit='s')
        else:
            curr_res = [pd.to_datetime(curr_time, unit='s')]
            # 整体信息
            basic_feature = get_basic_feature(curr_tx)
            curr_res.extend(basic_feature)
            # 庄家、散户行为
            maker_retail_feature = get_maker_retail_feature(curr_tx, maker_threshold)
            curr_res.extend(maker_retail_feature)
            # histogram
            hist = get_histogram_feature(curr_tx, histogram_threshold, bins)
            curr_res.extend(hist)

        features.append(curr_res)
        last_sum = curr_sum
        print(pd.to_datetime(curr_time, unit='s'))
        curr_time += 60 if minute_module else step_minute * 60

    columns_names = ['time']
    basic_feature_name = ['total_tx_count', 'std', 'skew', 'total_received', 'received_tx_count', 'total_send',
                          'send_tx_count']
    columns_names.extend(basic_feature_name)
    maker_retail_feature_name = ['maker_received', 'maker_received_tx_count', 'maker_send', 'maker_send_tx_count',
                                 'retail_received', 'retail_received_tx_count', 'retail_send', 'retail_send_tx_count']
    columns_names.extend(maker_retail_feature_name)
    hits_name = ['hist-' + str(e) for e in list(range(1, bins + 2, 1))]
    columns_names.extend(hits_name)
    feature_df = pd.DataFrame(features, columns=columns_names)
    feature_df.fillna(0, inplace=True)
    if return_dict is not None:
        return_dict[process_num] = feature_df
    return feature_df


if __name__ == '__main__':
    # exchange_data_path = 'temp/featureTestData.csv'
    exchange_data_path = '../data/okex.log'
    tx_data = pd.read_csv(exchange_data_path, header=-1, names=['time', 'value', 'tag', 'address'])
    # print tx_data
    tx_data['timestamp'] = pd.to_datetime(tx_data['time'], format="%Y%m%d%H%M%S").values.astype(np.int64) // 10 ** 9
    start_timestamp = 1527811200
    # 20180601030000 ~ 1527822000  20181101001000 ~ 1541031000
    end_timestamp = 1527822000
    # 20180601000000 ~ 20180601030000 2个小时内的数据，粒度为10分钟
    features_df = get_exchange_features(tx=tx_data,
                                        start_time=start_timestamp,
                                        end_time=end_timestamp,
                                        step_minute=10,
                                        bins=10,
                                        maker_threshold=5,
                                        value_threshold=1000)
    print(features_df)
    print(features_df.shape)
